<template>
  <div class="tts-container">
    <el-card class="tts-card" shadow="hover">
      <template #header>
        <div class="card-header">
          <span>语音合成配置</span>
        </div>
      </template>
      
      <!-- 文本输入区域 -->
      <el-form :model="form" label-width="120px" style="margin-bottom: 20px;">
        <el-form-item label="合成文本">
          <el-input
            v-model="form.text"
            type="textarea"
            :rows="4"
            placeholder="请输入要合成的文本内容，支持中英文混合..."
            maxlength="8000"
            show-word-limit
            :class="{ 'input-error': !isTextValid }"
          />
          <div class="text-info">
            <span v-if="form.text" class="estimated-duration">
              预估时长：{{ estimatedDuration }}
            </span>
            <span v-if="!isTextValid && form.text" class="text-error">
              文本长度不符合要求（1-8000字符）
            </span>
          </div>
        </el-form-item>
        
        <el-row :gutter="20">
          <el-col :span="8">
            <el-form-item label="发音人">
              <el-select v-model="form.voice" placeholder="选择发音人" filterable>
                <el-option 
                  v-for="option in VOICE_OPTIONS"
                  :key="option.value"
                  :label="option.label" 
                  :value="option.value" 
                />
              </el-select>
            </el-form-item>
          </el-col>
          
          <el-col :span="8">
            <el-form-item label="语速">
              <el-slider v-model="form.speed" :min="0" :max="100" :step="10" show-input />
            </el-form-item>
          </el-col>
          
          <el-col :span="8">
            <el-form-item label="音量">
              <el-slider v-model="form.volume" :min="0" :max="100" :step="10" show-input />
            </el-form-item>
          </el-col>
        </el-row>
        
        <el-row :gutter="20">
          <el-col :span="12">
            <el-form-item label="音调">
              <el-slider v-model="form.pitch" :min="0" :max="100" :step="10" show-input />
            </el-form-item>
          </el-col>
          
          <el-col :span="12">
            <el-form-item label="音频格式">
              <el-select v-model="form.audioFormat" placeholder="选择音频格式">
                <el-option 
                  v-for="option in AUDIO_FORMAT_OPTIONS"
                  :key="option.value"
                  :label="option.label" 
                  :value="option.value"
                >
                  <span>{{ option.label }}</span>
                  <span style="float: right; color: #8492a6; font-size: 13px;">{{ option.description }}</span>
                </el-option>
              </el-select>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      
      <!-- 控制按钮 -->
      <div class="button-group">
        <el-button 
          type="primary" 
          size="large"
          :loading="isConnecting"
          :disabled="!canStartSynthesis"
          @click="startSynthesis"
        >
          <el-icon><VideoPlay /></el-icon>
          {{ isConnecting ? '合成中...' : '开始合成' }}
        </el-button>
        
        <el-button 
          type="danger" 
          size="large"
          :disabled="!isConnecting"
          @click="stopSynthesis"
        >
          <el-icon><VideoPause /></el-icon>
          停止合成
        </el-button>
        
        <el-button 
          type="success" 
          size="large"
          :disabled="!hasAudio"
          @click="playAudio"
        >
          <el-icon><VideoPlay /></el-icon>
          播放音频
        </el-button>
        
        <el-button 
          type="warning" 
          size="large"
          :disabled="!hasAudio"
          @click="downloadAudio"
        >
          <el-icon><Download /></el-icon>
          下载音频
        </el-button>
      </div>
      
      <!-- 状态显示 -->
      <div class="status-area">
        <el-alert
          v-if="statusMessage"
          :title="statusMessage"
          :type="statusType"
          :closable="false"
          style="margin-bottom: 20px;"
        />
        
        <!-- 进度条 -->
        <el-progress
          v-if="isConnecting"
          :percentage="progress"
          :stroke-width="8"
          status="success"
        />
      </div>
      
      <!-- 音频播放器 -->
      <audio
        ref="audioPlayer"
        controls
        v-if="audioUrl"
        style="width: 100%; margin-top: 20px;"
      >
        <source :src="audioUrl" type="audio/wav" />
        您的浏览器不支持音频播放。
      </audio>
    </el-card>
  </div>
</template>

<script setup>
import { ref, reactive, computed, onUnmounted } from 'vue'
import { ElMessage } from 'element-plus'
import { VideoPlay, VideoPause, Download } from '@element-plus/icons-vue'
import { 
  generateAuthUrl, 
  generateTtsParams, 
  VOICE_OPTIONS, 
  AUDIO_FORMAT_OPTIONS,
  validateTextLength,
  estimateAudioDuration,
  getErrorMessage,
  WS_STATUS
} from '../utils/xunfeiApi'
import { 
  mergeAudioChunks, 
  createAudioBlob, 
  createAudioUrl, 
  downloadAudio as downloadAudioFile,
  pcmToWav,
  formatDuration 
} from '../utils/audioUtils'

// 响应式数据
const form = reactive({
  text: '你好，我是小月。欢迎使用科大讯飞语音合成工具，支持粤语发音。今天天气很好，希望你有愉快的一天！',
  voice: 'x3_xiaoyue',
  speed: 15,
  volume: 50,
  pitch: 50,
  audioFormat: 'lame'
})

const isConnecting = ref(false)
const statusMessage = ref('')
const statusType = ref('info')
const progress = ref(0)
const audioUrl = ref('')
const audioPlayer = ref(null)
const wsStatus = ref(WS_STATUS.CLOSED)

let ws = null
let audioData = []

// 计算属性
const isTextValid = computed(() => validateTextLength(form.text))
const estimatedDuration = computed(() => formatDuration(estimateAudioDuration(form.text, form.speed)))
const canStartSynthesis = computed(() => isTextValid.value && !isConnecting.value)
const hasAudio = computed(() => Boolean(audioUrl.value))

// TTS合成功能

// 开始语音合成
const startSynthesis = async () => {
  if (!isTextValid.value) {
    ElMessage.warning('请输入有效的文本内容（1-8000字符）')
    return
  }
  
  try {
    isConnecting.value = true
    progress.value = 0
    statusMessage.value = '正在连接语音合成服务...'
    statusType.value = 'info'
    wsStatus.value = WS_STATUS.CONNECTING
    audioData = []
    
    // 清理之前的音频URL
    if (audioUrl.value) {
      URL.revokeObjectURL(audioUrl.value)
      audioUrl.value = ''
    }
    
    // 生成WebSocket URL
    const wsUrl = generateAuthUrl()
    
    // 创建WebSocket连接
    ws = new WebSocket(wsUrl)
    
    ws.onopen = () => {
      statusMessage.value = '连接成功，正在发送合成请求...'
      statusType.value = 'info'
      progress.value = 20
      wsStatus.value = WS_STATUS.CONNECTED
      
      // 发送合成参数
      const params = generateTtsParams({
        text: form.text,
        voice: form.voice,
        speed: form.speed,
        volume: form.volume,
        pitch: form.pitch,
        audioFormat: form.audioFormat
      })
      
      ws.send(JSON.stringify(params))
      wsStatus.value = WS_STATUS.SYNTHESIZING
    }
    
    ws.onmessage = (event) => {
      const response = JSON.parse(event.data)
      
      if (response.code !== 0) {
        const errorMsg = getErrorMessage(response.code) || response.message
        throw new Error(`合成失败: ${errorMsg}`)
      }
      
      if (response.data && response.data.audio) {
        // 接收到音频数据
        const audioBase64 = response.data.audio
        const audioBytes = atob(audioBase64)
        const audioArray = new Uint8Array(audioBytes.length)
        
        for (let i = 0; i < audioBytes.length; i++) {
          audioArray[i] = audioBytes.charCodeAt(i)
        }
        
        audioData.push(audioArray)
        
        // 根据数据状态更新进度
        if (response.data.status === 1) {
          progress.value = Math.min(progress.value + 10, 80)
        } else if (response.data.status === 2) {
          progress.value = 90
        }
      }
      
      if (response.data && response.data.status === 2) {
        // 合成完成
        progress.value = 100
        statusMessage.value = '语音合成完成！'
        statusType.value = 'success'
        wsStatus.value = WS_STATUS.COMPLETED
        
        // 合并音频数据
        const combinedArray = mergeAudioChunks(audioData)
        
        // 如果是PCM格式，转换为WAV
        let audioBlob
        if (form.audioFormat === 'raw') {
          const wavBuffer = pcmToWav(combinedArray.buffer)
          audioBlob = createAudioBlob(new Uint8Array(wavBuffer), 'audio/wav')
        } else {
          audioBlob = createAudioBlob(combinedArray, `audio/${form.audioFormat}`)
        }
        
        audioUrl.value = createAudioUrl(audioBlob)
        
        ws.close()
        isConnecting.value = false
        
        ElMessage.success(`语音合成成功！预估时长：${estimatedDuration.value}`)
      }
    }
    
    ws.onerror = (error) => {
      console.error('WebSocket错误:', error)
      statusMessage.value = '连接失败，请检查网络连接'
      statusType.value = 'error'
      wsStatus.value = WS_STATUS.ERROR
      isConnecting.value = false
      ElMessage.error('语音合成失败')
    }
    
    ws.onclose = () => {
      isConnecting.value = false
      wsStatus.value = WS_STATUS.CLOSED
    }
    
  } catch (error) {
    console.error('合成失败:', error)
    statusMessage.value = `合成失败: ${error.message}`
    statusType.value = 'error'
    wsStatus.value = WS_STATUS.ERROR
    isConnecting.value = false
    ElMessage.error('语音合成失败')
  }
}

// 停止合成
const stopSynthesis = () => {
  if (ws) {
    ws.close()
  }
  isConnecting.value = false
  statusMessage.value = '合成已停止'
  statusType.value = 'warning'
  progress.value = 0
}

// 播放音频
const playAudio = () => {
  if (audioPlayer.value) {
    audioPlayer.value.play()
  }
}

// 下载音频
const downloadAudio = () => {
  if (audioUrl.value) {
    const filename = `科大讯飞TTS_${new Date().toISOString().slice(0, 19).replace(/:/g, '-')}.wav`
    downloadAudioFile(audioUrl.value, filename)
    ElMessage.success('音频下载成功！')
  }
}

// 组件卸载时清理
onUnmounted(() => {
  if (ws) {
    ws.close()
  }
  if (audioUrl.value) {
    URL.revokeObjectURL(audioUrl.value)
  }
})
</script>

<style scoped>
.tts-container {
  max-width: 1200px;
  margin: 0 auto;
}

.tts-card {
  border-radius: 15px;
  box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
}

.card-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-size: 18px;
  font-weight: bold;
  color: #409EFF;
}

.button-group {
  display: flex;
  gap: 15px;
  justify-content: center;
  margin-bottom: 20px;
  flex-wrap: wrap;
}

.status-area {
  margin-top: 20px;
}

.el-slider {
  margin-top: 12px;
}

.text-info {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 8px;
  font-size: 12px;
}

.estimated-duration {
  color: #409EFF;
  font-weight: 500;
}

.text-error {
  color: #F56C6C;
  font-weight: 500;
}

.input-error :deep(.el-textarea__inner) {
  border-color: #F56C6C;
}

.input-error :deep(.el-textarea__inner):focus {
  border-color: #F56C6C;
  box-shadow: 0 0 0 2px rgba(245, 108, 108, 0.2);
}

@media (max-width: 768px) {
  .button-group {
    flex-direction: column;
    align-items: center;
  }
  
  .button-group .el-button {
    width: 200px;
  }
  
  .text-info {
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
  }
}
</style> 